<?php
/**
 * 功能节点控制器（优化版）
 * RESTful API 实现系统功能节点管理
 */

declare (strict_types = 1);

namespace app\controller\home;

use app\BaseController;
use think\facade\Db;
use think\facade\Request;
use app\common\DataPermissionHelper;

class RuleOptimized extends BaseController
{
    /**
     * 获取功能节点列表（向后兼容方法）
     */
    public function index()
    {
        return $this->list();
    }
    
    /**
     * 获取功能节点列表
     * GET /api/home/rule/list
     */
    public function list()
    {
        try {
            $param = Request::param();
            $page = (int)($param['page'] ?? 1);
            $limit = (int)($param['limit'] ?? 20);
            $keywords = trim($param['keywords'] ?? '');
            $module = trim($param['module'] ?? '');
            $menu = $param['menu'] ?? '';
            $status = $param['status'] ?? '';
            $pid = isset($param['pid']) ? (int)$param['pid'] : null; // 父节点ID筛选
            $withLevel = $param['withLevel'] ?? false; // 是否需要层级信息
            $tree = $param['tree'] ?? false; // 是否返回树形结构
            
            // 构建查询条件
            $where = [];
            
            // 关键词搜索
            if (!empty($keywords)) {
                $where[] = ['ar.title|ar.name|ar.src', 'like', '%' . $keywords . '%'];
            }
            
            // 按模块筛选
            if (!empty($module)) {
                $where[] = ['ar.module', '=', $module];
            }
            
            // 按菜单类型筛选
            if ($menu !== '') {
                $where[] = ['ar.menu', '=', (int)$menu];
            }
            
            // 按状态筛选
            if ($status !== '') {
                $where[] = ['ar.status', '=', (int)$status];
            }
            
            // 按父节点ID筛选（仅在非树形结构模式下使用）
            if ($pid !== null && !$tree) {
                $where[] = ['ar.pid', '=', $pid];
            }
            
            // 权限检查：只有超级管理员才能查看所有节点
            if (!$this->checkSuperAdmin()) {
                return $this->error('无权限查看功能节点', 403);
            }
            
            // 查询功能节点列表
            $query = Db::name('admin_rule')
                ->field('ar.*, am.title as module_title')
                ->alias('ar')
                ->leftJoin('admin_module am', 'ar.module = am.name')
                ->where($where)
                ->order('ar.sort asc, ar.id asc');
                
            // 是否需要分页
            if ($tree) {
                // 获取所有数据，用于构建树形结构
                $allRules = $query->select()->toArray();
                
                // 是否指定了父节点ID
                if ($pid !== null && $pid > 0) {
                    // 如果指定了父节点且父节点ID大于0，则只构建该节点及其子节点的树
                    $startLevel = 0;
                    // 查询父节点信息，确定开始层级
                    $parentNode = Db::name('admin_rule')->where('id', $pid)->find();
                    if ($parentNode) {
                        // 父节点存在，则其子节点从下一层级开始
                        $parentLevel = $this->getNodeLevel($parentNode, $allRules);
                        $startLevel = $parentLevel + 1;
                    }
                    $list = $this->generateTree($allRules, $pid, $startLevel);
                } else {
                    // 构建完整树形结构，从顶级节点开始
                    $list = $this->generateTree($allRules, 0, 0);
                }
                
                return $this->success($list, '获取功能节点树成功');
            } else {
                // 分页查询
                $total = $query->count();
                $rules = $query->page($page, $limit)->select()->toArray();
                
                // 格式化数据
                foreach ($rules as &$rule) {
                    // 添加层级信息
                    if ($withLevel && $rule['pid'] == 0) {
                        $rule['level'] = 0;
                    } elseif ($withLevel) {
                        // 获取当前节点层级
                        $rule['level'] = $this->getNodeLevel($rule, $query->select()->toArray());
                    }
                    
                    $rule = $this->formatRuleData($rule);
                }
                
                return $this->paginate($rules, $total, $page, $limit, '获取功能节点列表成功');
            }
        } catch (\Exception $e) {
            return $this->error('查询失败: ' . $e->getMessage(), 500);
        }
    }
    
    /**
     * 获取节点的层级
     * @param array $node 当前节点
     * @param array $allNodes 所有节点
     * @return int 节点层级，顶级为0
     */
    private function getNodeLevel($node, $allNodes) {
        if (!$node || $node['pid'] == 0) {
            return 0;
        }
        
        // 查找父节点
        $parentNode = null;
        foreach ($allNodes as $n) {
            if ($n['id'] == $node['pid']) {
                $parentNode = $n;
                break;
            }
        }
        
        if (!$parentNode) {
            return 1; // 找不到父节点，默认为二级节点
        }
        
        // 递归获取父节点的层级，并加1
        return $this->getNodeLevel($parentNode, $allNodes) + 1;
    }
    
    /**
     * 生成树形结构
     * @param array $list 节点列表
     * @param int $pid 父节点ID
     * @param int $level 当前层级，顶级为0
     * @return array 树形结构数组
     */
    private function generateTree($list, $pid = 0, $level = 0)
    {
        $tree = [];
        foreach ($list as $item) {
            if ($item['pid'] == $pid) {
                // 添加层级属性
                $item['level'] = $level;
                // 递归获取子节点，并将层级+1
                $item['children'] = $this->generateTree($list, $item['id'], $level + 1);
                // 如果有子节点，设置hasChildren属性
                $item['hasChildren'] = !empty($item['children']);
                $item = $this->formatRuleData($item);
                $tree[] = $item;
            }
        }
        return $tree;
    }
    
    /**
     * 格式化节点数据
     */
    private function formatRuleData($rule)
    {
        $rule['create_time_format'] = $rule['create_time'] ? date('Y-m-d H:i:s', $rule['create_time']) : '';
        $rule['update_time_format'] = $rule['update_time'] ? date('Y-m-d H:i:s', $rule['update_time']) : '';
        
        // 菜单类型
        $menuTypes = [
            1 => '是',
            2 => '否'
        ];
        $rule['menu_name'] = $menuTypes[$rule['menu']] ?? '未知';
        
        // 状态
        $statusNames = [
            0 => '禁用',
            1 => '正常'
        ];
        $rule['status_name'] = $statusNames[$rule['status']] ?? '未知';
        
        // 确保层级属性存在
        if (!isset($rule['level'])) {
            // 如果没有level属性，根据pid设置默认值
            $rule['level'] = $rule['pid'] == 0 ? 0 : 1;
        }
        
        return $rule;
    }
    
    /**
     * 查看单个功能节点详情
     * GET /api/home/rule/{id}
     */
    public function read()
    {
        try {
            $param = Request::param();
            $id = (int)($param['id'] ?? 0);
            
            if ($id <= 0) {
                return $this->paramError('节点ID不能为空');
            }
            
            // 权限检查
            if (!$this->checkSuperAdmin()) {
                return $this->error('无权限查看功能节点', 403);
            }
            
            // 查询节点详情
            $rule = Db::name('admin_rule')
                ->field('ar.*, am.title as module_title')
                ->alias('ar')
                ->leftJoin('admin_module am', 'ar.module = am.name')
                ->where('ar.id', $id)
                ->find();
            
            if (empty($rule)) {
                return $this->error('功能节点不存在', 404);
            }
            
            $rule = $this->formatRuleData($rule);
            
            // 获取父节点信息
            if ($rule['pid'] > 0) {
                $parentRule = Db::name('admin_rule')
                    ->where('id', $rule['pid'])
                    ->field('id, title')
                    ->find();
                $rule['parent_name'] = $parentRule['title'] ?? '';
            }
            
            // 获取子节点数量
            $rule['children_count'] = Db::name('admin_rule')
                ->where('pid', $id)
                ->count();
            
            return $this->success($rule, '获取功能节点详情成功');
        } catch (\Exception $e) {
            return $this->error('查询失败: ' . $e->getMessage(), 500);
        }
    }
    
    /**
     * 创建功能节点
     * POST /api/home/rule
     */
    public function save()
    {
        try {
            $param = Request::param();
            
            // 权限检查（只有超级管理员才能操作）
            if (!$this->checkSuperAdmin()) {
                return $this->error('只有系统超级管理员才有权限操作节点！', 403);
            }
            
            // 数据验证
            $validate = $this->validateRuleData($param);
            if ($validate !== true) {
                return $this->paramError($validate);
            }
            
            // 检查节点是否已存在
            $existRule = Db::name('admin_rule')
                ->where('src', trim($param['src']))
                ->where('module', $param['module'])
                ->find();
            
            if ($existRule) {
                return $this->error('该节点链接在此模块下已存在', 400);
            }
            
            $data = [
                'pid' => (int)($param['pid'] ?? 0),
                'src' => trim($param['src']),
                'title' => trim($param['title']),
                'name' => trim($param['name'] ?? ''),
                'module' => $param['module'],
                'icon' => trim($param['icon'] ?? ''),
                'menu' => (int)($param['menu'] ?? 2),
                'sort' => (int)($param['sort'] ?? 1),
                'status' => (int)($param['status'] ?? 1),
                'create_time' => time(),
                'update_time' => time()
            ];
            
            // 创建功能节点
            $ruleId = Db::name('admin_rule')->insertGetId($data);
            
            // 确保超级管理员角色拥有所有节点权限
            $this->ensureSuperAdminHasAllRules($ruleId);
            
            return $this->created(['id' => $ruleId], '功能节点创建成功');
        } catch (\Exception $e) {
            return $this->error('创建失败: ' . $e->getMessage(), 500);
        }
    }

    /**
     * 确保超级管理员角色拥有所有节点权限
     * @param int $ruleId 新创建的节点ID，如果为0则表示需要更新所有节点权限
     */
    private function ensureSuperAdminHasAllRules($ruleId = 0)
    {
        // 获取超级管理员角色
        $superAdminRole = Db::name('admin_group')->where('id', 1)->find();
        
        if (!$superAdminRole) {
            return;
        }
        
        // 如果传入了特定的ruleId，只需确保该节点在超级管理员权限中
        if ($ruleId > 0) {
            $rules = trim($superAdminRole['rules'], ',');
            $rulesArray = explode(',', $rules);
            
            // 如果该节点ID还不在超级管理员权限中，则添加
            if (!in_array($ruleId, $rulesArray)) {
                $rulesArray[] = $ruleId;
                $newRules = ',' . implode(',', $rulesArray) . ',';
                Db::name('admin_group')->where('id', 1)->update(['rules' => $newRules]);
            }
        } else {
            // 如果没有传入ruleId，需要确保超级管理员拥有所有节点权限
            $allRules = Db::name('admin_rule')->column('id');
            $newRules = ',' . implode(',', $allRules) . ',';
            Db::name('admin_group')->where('id', 1)->update(['rules' => $newRules]);
        }
    }
    
    /**
     * 更新功能节点
     * PUT /api/home/rule/{id}
     */
    public function update()
    {
        try {
            $param = Request::param();
            $id = (int)($param['id'] ?? 0);
            
            if ($id <= 0) {
                return $this->paramError('节点ID不能为空');
            }
            
            // 权限检查
            if (!$this->checkSuperAdmin()) {
                return $this->error('只有系统超级管理员才有权限操作节点！', 403);
            }
            
            // 检查节点是否存在
            $rule = Db::name('admin_rule')->where('id', $id)->find();
            if (empty($rule)) {
                return $this->error('功能节点不存在', 404);
            }
            
            // 数据验证
            $validate = $this->validateRuleData($param, $id);
            if ($validate !== true) {
                return $this->paramError($validate);
            }
            
            // 检查节点是否已存在（排除自己）
            $existRule = Db::name('admin_rule')
                ->where('src', trim($param['src']))
                ->where('module', $param['module'])
                ->where('id', '<>', $id)
                ->find();
            
            if ($existRule) {
                return $this->error('该节点链接在此模块下已存在', 400);
            }
            
            $data = [
                'pid' => (int)($param['pid'] ?? $rule['pid']),
                'src' => trim($param['src']),
                'title' => trim($param['title']),
                'name' => trim($param['name'] ?? $rule['name']),
                'module' => $param['module'],
                'icon' => trim($param['icon'] ?? $rule['icon']),
                'menu' => (int)($param['menu'] ?? $rule['menu']),
                'sort' => (int)($param['sort'] ?? $rule['sort']),
                'status' => (int)($param['status'] ?? $rule['status']),
                'update_time' => time()
            ];
            
            // 更新功能节点
            Db::name('admin_rule')->where('id', $id)->update($data);
            
            return $this->success('功能节点更新成功');
        } catch (\Exception $e) {
            return $this->error('更新失败: ' . $e->getMessage(), 500);
        }
    }
    
    /**
     * 删除功能节点
     * DELETE /api/home/rule/{id}
     */
    public function delete()
    {
        try {
            $param = Request::param();
            $id = (int)($param['id'] ?? 0);
            
            if ($id <= 0) {
                return $this->paramError('节点ID不能为空');
            }
            
            // 权限检查
            if (!$this->checkSuperAdmin()) {
                return $this->error('只有系统超级管理员才有权限操作节点！', 403);
            }
            
            // 检查节点是否存在
            $rule = Db::name('admin_rule')->where('id', $id)->find();
            if (empty($rule)) {
                return $this->error('功能节点不存在', 404);
            }
            
            // 检查是否有子节点
            $childCount = Db::name('admin_rule')->where('pid', $id)->count();
            if ($childCount > 0) {
                return $this->error('该节点下还有子节点，请先删除子节点', 400);
            }
            
            // 删除节点
            Db::name('admin_rule')->where('id', $id)->delete();
            
            return $this->deleted('功能节点删除成功');
        } catch (\Exception $e) {
            return $this->error('删除失败: ' . $e->getMessage(), 500);
        }
    }
    
    /**
     * 验证节点数据
     * @param array $param 请求参数
     * @param int $id 节点ID（编辑时使用）
     * @return bool|string 验证通过返回true，否则返回错误信息
     */
    private function validateRuleData($param, $id = 0)
    {
        if (empty($param['title'])) {
            return '节点名称不能为空';
        }
        
        if (empty($param['src'])) {
            return '节点链接不能为空';
        }
        
        if (empty($param['module'])) {
            return '所属模块不能为空';
        }
        
        // 验证菜单类型
        if (isset($param['menu']) && !in_array($param['menu'], [1, 2])) {
            return '菜单类型只能是1（是）或2（否）';
        }
        
        // 验证状态
        if (isset($param['status']) && !in_array($param['status'], [0, 1])) {
            return '状态只能是0（禁用）或1（正常）';
        }
        
        return true;
    }
    
    /**
     * 获取菜单节点列表（向后兼容方法）
     */
    public function rule_list()
    {
        try {
            $param = Request::param();
            $page = isset($param['page']) ? (int)$param['page'] : 1;
            $limit = isset($param['limit']) ? (int)$param['limit'] : 10;
            
            // 查询菜单节点列表
            $list = Db::name('admin_rule')
                ->field('a.*,m.title as module_title')
                ->alias('a')
                ->leftJoin('admin_module m', 'a.module = m.name')
                ->order('a.sort asc,a.id asc')
                ->page($page, $limit)
                ->select()
                ->each(function($item) {
                    // 格式化时间
                    $item['create_time'] = date('Y-m-d H:i', $item['create_time']);
                    return $item;
                });
            
            // 查询总数
            $count = Db::name('admin_rule')
                ->alias('a')
                ->count();
            
            // 生成树形结构
            $tree = $this->generateTree($list->toArray());
            
            return json([
                'code' => 0,
                'msg' => 'success',
                'data' => $tree,
                'count' => $count
            ]);
        } catch (\Exception $e) {
            return json(['code' => 500, 'msg' => '查询失败: ' . $e->getMessage()]);
        }
    }
    
    /**
     * 查看单个菜单节点信息（向后兼容方法）
     */
    public function rule_view()
    {
        $param = Request::param();
        
        if (empty($param['id'])) {
            return json(['code' => 400, 'msg' => '参数错误']);
        }
        
        try {
            $rule = Db::name('admin_rule')
                ->field('a.*,m.title as module_title')
                ->alias('a')
                ->leftJoin('admin_module m', 'a.module = m.name')
                ->where('a.id', $param['id'])
                ->find();
            
            if (empty($rule)) {
                return json(['code' => 404, 'msg' => '菜单节点不存在']);
            }
            
            // 格式化时间
            $rule['create_time'] = date('Y-m-d H:i', $rule['create_time']);
            
            return json([
                'code' => 0,
                'msg' => 'success',
                'data' => $rule
            ]);
        } catch (\Exception $e) {
            return json(['code' => 500, 'msg' => '查询失败: ' . $e->getMessage()]);
        }
    }
    
    /**
     * 新建菜单节点（向后兼容方法）
     */
    public function rule_add()
    {
        $param = Request::param();
        
        // 数据验证
        if (empty($param['title'])) {
            return json(['code' => 400, 'msg' => '节点名称不能为空']);
        }
        
        // 如果不是菜单类型(menu=1)，则要求src不能为空
        // 菜单类型节点允许src为空
        $menu = $param['menu'] ?? 1;
        if (empty($param['src']) && $menu !== 1) {
            return json(['code' => 400, 'msg' => '节点路径不能为空']);
        }
        
        $data = [
            'pid' => $param['pid'] ?? 0,
            'title' => $param['title'],
            'icon' => $param['icon'] ?? '',
            'src' => preg_replace('# #', '', $param['src']),
            'module' => $param['module'] ?? '',
            'menu' => $param['menu'] ?? 1,
            'sort' => $param['sort'] ?? 0,
            'status' => $param['status'] ?? 1,
            'create_time' => time(),
            'update_time' => time()
        ];
        
        try {
            $ruleId = Db::name('admin_rule')->insertGetId($data);
            
            // 自动为系统所有者管理组分配新增的节点
            $group = Db::name('admin_group')->find(1);
            if (!empty($group)) {
                $newGroup = [
                    'id' => 1,
                    'rules' => $group['rules'] . ',' . $ruleId
                ];
                Db::name('admin_group')->update($newGroup);
            }
            
            // 删除后台节点缓存
            // clear_cache('adminRules');
            
            return json(['code' => 0, 'msg' => '添加成功', 'data' => ['id' => $ruleId]]);
        } catch (\Exception $e) {
            return json(['code' => 500, 'msg' => '添加失败: ' . $e->getMessage()]);
        }
    }
    
    /**
     * 编辑菜单节点（向后兼容方法）
     */
    public function rule_edit()
    {
        $param = Request::param();
        
        // 数据验证
        if (empty($param['id'])) {
            return json(['code' => 400, 'msg' => '参数错误']);
        }
        
        if (empty($param['title'])) {
            return json(['code' => 400, 'msg' => '节点名称不能为空']);
        }
        
        if (empty($param['src'])) {
            return json(['code' => 400, 'msg' => '节点路径不能为空']);
        }
        
        // 检查菜单节点是否存在
        $rule = Db::name('admin_rule')->where('id', $param['id'])->find();
        if (empty($rule)) {
            return json(['code' => 404, 'msg' => '菜单节点不存在']);
        }
        
        // 检查节点路径是否已存在（排除自己）
        $exist = Db::name('admin_rule')
            ->where('src', $param['src'])
            ->where('id', '<>', $param['id'])
            ->find();
        
        if ($exist) {
            return json(['code' => 400, 'msg' => '节点路径已存在']);
        }
        
        $data = [
            'id' => $param['id'],
            'pid' => $param['pid'] ?? $rule['pid'],
            'title' => $param['title'],
            'icon' => $param['icon'] ?? $rule['icon'],
            'src' => preg_replace('# #', '', $param['src']),
            'module' => $param['module'] ?? $rule['module'],
            'menu' => $param['menu'] ?? $rule['menu'],
            'sort' => $param['sort'] ?? $rule['sort'],
            'status' => $param['status'] ?? $rule['status'],
            'update_time' => time()
        ];
        
        try {
            // 更新菜单节点
            Db::name('admin_rule')->update($data);
            
            // 删除后台节点缓存
            // clear_cache('adminRules');
            
            return json(['code' => 0, 'msg' => '更新成功']);
        } catch (\Exception $e) {
            return json(['code' => 500, 'msg' => '更新失败: ' . $e->getMessage()]);
        }
    }
    
    /**
     * 删除菜单节点（向后兼容方法）
     */
    public function rule_del()
    {
        $param = Request::param();
        
        // 数据验证
        if (empty($param['id'])) {
            return json(['code' => 400, 'msg' => '参数错误']);
        }
        
        // 检查菜单节点是否存在
        $rule = Db::name('admin_rule')->where('id', $param['id'])->find();
        if (empty($rule)) {
            return json(['code' => 404, 'msg' => '菜单节点不存在']);
        }
        
        // 检查是否有子节点
        $childCount = Db::name('admin_rule')->where('pid', $param['id'])->count();
        if ($childCount > 0) {
            return json(['code' => 400, 'msg' => '该节点下还有子节点，请先删除子节点']);
        }
        
        try {
            // 删除菜单节点
            Db::name('admin_rule')->where('id', $param['id'])->delete();
            
            // 删除后台节点缓存
            // clear_cache('adminRules');
            
            return json(['code' => 0, 'msg' => '删除成功']);
        } catch (\Exception $e) {
            return json(['code' => 500, 'msg' => '删除失败: ' . $e->getMessage()]);
        }
    }
}